package com.dongzili.demo.common.utils;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import com.dongzili.demo.common.vo.ReflectClassInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 实体字段反射信息缓存
 */

@Configuration
@Slf4j
@AutoConfigureAfter(SpringUtil.class)
public class ReflectionCache {

//    private static final String REDIS_KEY = "reflect_class_info";
    private static final List<String> BASE_PACKAGES = Arrays.asList(
            "com.dongzili.demo.common"
            ,"com.dongzili.demo.customer"
    );


    @PostConstruct
    public void init() {
        for (String packageName : BASE_PACKAGES) {
            if (!StringUtils.hasText(packageName)) {
                continue;
            }
            // 扫描数据库实体，根据实体创建对应 mapper、service
            Set<Class<?>> entityClassSet = ClassUtil.scanPackage(packageName);
            if (entityClassSet.isEmpty()) {
                continue;
            }
            for (Class<?> entityClass : entityClassSet) {
                // 只创建带有 MapAndService 注解的实体
                TableName tableName = entityClass.getAnnotation(TableName.class);
                if (tableName == null) {
                    continue;
                }
                ReflectClassInfo<?> reflectClassInfo = new ReflectClassInfo<>(entityClass);
                reflectClassInfoMap.put(entityClass, reflectClassInfo);
            }
        }
        System.out.println("反射信息缓存初始化完成"+reflectClassInfoMap.size()+"个, 实体类:"+reflectClassInfoMap.keySet());
    }

    private static final Map<Class<?>, ReflectClassInfo<?>> reflectClassInfoMap = new ConcurrentHashMap<>();
    /**
     * 获取实体类对应的 反射 信息
     * @param clazz 实体类
     * @param <T> 实体类类型
     * @return 反射信息
     */
    public static <T> ReflectClassInfo<T> getReflectClassInfo(Class<T> clazz) {
        if (clazz != null) {
            ReflectClassInfo<?> reflectClassInfo = reflectClassInfoMap.get(clazz);
            if(reflectClassInfo == null) {
                return new ReflectClassInfo<>(clazz);
            }
            return (ReflectClassInfo<T>) reflectClassInfo;
        }
        return null;
    }

    /**
     * 获取实体类的主键值
     * @param t 实体类
     * @return 主键值
     * @param <T> 实体类类型
     */
    public static <T> Serializable getPrimaryValue(T t){
        ReflectClassInfo<?> reflectClassInfo = ReflectionCache.getReflectClassInfo(t.getClass());
        if (reflectClassInfo == null) {
            return null;
        }
        try{
            return (Serializable) reflectClassInfo.getPrimaryField().get(t);
        }catch (Exception e){
            return null;
        }
    }

}
